<template>
	<view class="file">
		<view class="uploadGroup">
			<view class="box" v-for="(item,index) in temFiles" :key="index">
				<image :src="reTemFileUrl == '' ? item.path : reTemFileUrl" mode="aspectFill" @click="clickImg(index)"></image>
				<view class="close" @click="onClose(index)">×</view>
			</view>
			<view class="box add" @click="addFile" v-if="temFiles.length < mSize">+</view>
			<text class="tips" v-else-if="mSize!=1">一次最多上传{{mSize}}张</text>
		</view>
	</view>
</template>

<script setup>
	/**
	 * 传入属性: 
	 * 		value	v-model绑定	空/ok	标识是否本地上传了图片,供表单校验
	 * 		maxSize 最大上传图片数量默认1		app/某些h5 只能单选或多选
	 * 		cloudPath	上传到云存储的文件夹, 路径例如 a, a/b
	 * 暴露的属性和方法:
	 * 		goUpload()	上传;	返回上传后返回的图片url字符串或数组
	 * 		clearImageList()	清空图片列表
	 * 		fileIDArr	上传后的图片url或数组
	 * 		temFiles	本地图片列表
	 * 可触发事件
	 * 		update:modelValue	v-model绑定
	 * 		upload	本地添加图片后触发, 参数为本地图片列表
	 * 
	 * 注:支付宝云与腾讯云返回的为cloud://形式,需要调用getTempFileURL获取链接
	 * 
	 */
	import {
		ref, watch
	} from 'vue'
	import { onLoad } from '@dcloudio/uni-app'
	import { cloudToUrl,unique } from '@/utils/common.js'
	const props = defineProps({
		value:{
			type: String,
			default: '' // v-model绑定 上传本地后的图片url
		},
		maxSize: {
			type: Number,
			default: 1 //最大上传图片数量
		},
		// reTemFile:{
		// 	type: Object,
		// 	default: () => {
		// 		return {
		// 			url:'',	//网络地址
		// 			name:'',	//文件名
		// 			path:''	//cloud地址
		// 		}
		// 	}
		// },
		cloudPath:{
			type: String,
			default: '' //上传到云存储的文件夹
		},
		autoUpLoad:{
			type: Boolean,
			default: false //是否自动上传
		},
		randomFileName:{
			type: Boolean,
			default: false
		}
	})
	
	const mSize = ref(1)
	onLoad(()=>{	
		mSize.value = props.maxSize
		// #ifdef APP || MP
		mSize.value = 1
		// #endif
	})
	
	// upload 上传图片后触发
	const emit = defineEmits(['update:modelValue','upload'])
	
	const temFiles = ref([]) //通过temFiles渲染图片显示
	let reTemFileUrl = ref('')	// 回显时的图片地址
	// watch(
	//   () => props.reTemFile,
	//   (newVal) => {
	// 	  if(newVal.path !== ''){
	// 		temFiles.value[0] = newVal
	// 		reTemFileUrl.value =  newVal.url
	// 	  }
	//   },
	//   { immediate: true } // 立即执行，保证组件加载时检测到props的初始值
	// )
	
	const addFile = () => { //点击+号上传图片的事件回调
		uni.chooseImage({
			count: mSize.value, //默认9
			sizeType: ['original'], //可以指定是原图还是压缩图，默认二者都有
			sourceType: ['album'], //从相册选择
			success: (res) => {
				// console.log(res);
				temFiles.value = [...temFiles.value, ...res.tempFiles].slice(0, 9) //多次上传追加图片
				// 去重
				temFiles.value = unique(temFiles.value,'name')
				const num = temFiles.value.length - mSize.value
				if(num > 0){
					// 去掉数组最后几个
					temFiles.value.splice(mSize.value, num)
				}
				// console.log('本地文件列表 temFiles',temFiles.value);
				emit('upload',temFiles.value)
				// console.log(temFiles.value)
				// 上传了本地就返回标识，供表单校验
				// if(props.maxSize>1){
				// 	emit('update:modelValue','ok')
				// }else{
				// 	emit('update:modelValue','ok')
				// }
				emit('update:modelValue','ok')
				
				// console.log(props.autoUpLoad);
				if(props.autoUpLoad){
					// console.log('autoUpLoad');
					goUpload().then(res => {
						// console.log('res',res);
						return res
					}).catch(err => {
						// console.log('err',err);
						return err
					})
				}
			}
		})
		
	}
	// 删除按钮
	const onClose = (e) => {
		reTemFileUrl.value = ''
		temFiles.value.splice(e, 1)
		if(temFiles.value.length == 0){
			emit('update:modelValue','')
		}
	}
	// 清空
	const clearImageList = () =>{
		reTemFileUrl.value = ''
		temFiles.value = []
		emit('update:modelValue','')
	}

	// 点击图片查看大图
	const clickImg = (e) => {
		const arr = temFiles.value.map(item => item.path)
		uni.previewImage({
			urls: arr,
			current: e
		})
	}


	let fileIDArr = [] // 上传到云存储中存放的路径
	// 点击上传
	const goUpload = () => {
		// console.log('run goUpload');
		return new Promise((resolve, reject) => {
			const promiseArr = temFiles.value.map(item => {
				// #ifdef MP
				const fileName = item.path.split('/').pop(); // 提取文件名
				const currentTime = new Date(); // 获取当前时间
				item = {
					path: item.path,
					lastModified: currentTime.getTime(),
					lastModifiedDate: currentTime,
					name: fileName,
					size: item.size,
					type: `image/${fileName.split('.').pop()}` // 根据文件扩展名设置类型
				}
				// #endif
				return uploadFun(item)
			});

			// console.log(promiseArr);
			// console.log(arr);	//promise对象组成的数组
			Promise.all(promiseArr).then(res => {
				// console.log(promiseArr);	//所有promise对象都成功后返回的结果数组
				// console.log(res);
				fileIDArr = res.map(item => {
					return item.fileID
				})
				if(props.maxSize > 1){
					// console.log('## resolve', fileIDArr);
					resolve(fileIDArr)
					// console.log(fileIDArr);
				}else{
					// console.log('## resolve', fileIDArr[0]);
					resolve(fileIDArr[0])
					// console.log(fileIDArr[0]);
				}
				// console.log(fileIDArr);
				
			}).catch(err => {
				// console.log(err);
				reject({
					source: 'components: upload-image error',
					msg: err
				})
			})
		})
	}

	// 上传函数 用于上传单个文件
	const uploadFun = (e) => {
		const parts = e.name.split('.');
		const extension = parts.length > 1 ? parts[parts.length - 1] : null
		let fileName = e.name
		if(props.randomFileName){
			fileName = generateLongFileName(extension)
		}
		// 返回premise对象
		return uniCloud.uploadFile({
			// cloudPathAsRealPath: true,
			filePath: e.path, // 本地文件路径
			cloudPath: `${props.cloudPath}/${fileName}` // 云端文件名
			// cloudPath: e.name // 云端文件名
		})

	}
	
	const generateLongFileName = (extension = '') => {
	  // 获取当前时间戳并混淆（与一个随机数异或，结果转为16进制）
	  const timestamp = (Date.now() ^ Math.floor(Math.random() * 1000000)).toString(16);
	  // 生成更长的随机字符串（16位）
	  const randomStr = Math.random().toString(36).substring(2, 18);
	  // 混合时间戳和随机字符串，增加文件名长度
	  const fileName = `${randomStr}${timestamp}`;
	  // 如果需要扩展名，拼接后返回
	  return extension ? `${fileName}.${extension.replace(/^\./, '')}` : fileName;
	}
	// 示例调用
	// console.log(generateLongFileName('png')); // 例如：x9y2b3w4hzq5r7jfc21b8a1b34d.png
	// console.log(generateLongFileName());      // 例如：a7f9j0o9p32k8b5x92b2w78df0a
	
	
	defineExpose({
		goUpload,	//上传
		fileIDArr,	//上传后的图片url
		clearImageList,		// 清空
		temFiles		// 上传的图片本地路径
	})
</script>

<style lang="scss" scoped>
	.tips{
		color: #ff5234;
		padding-left: 30rpx;
	}
	.uploadGroup {
		padding: 30rpx;
		display: flex;
		flex-wrap: wrap;

		.box {
			width: 200rpx;
			height: 200rpx;
			background: #eee;
			margin-right: 15rpx;
			margin-bottom: 15rpx;
			position: relative;
			cursor: pointer;

			image {
				width: 100%;
				height: 100%;
			}

			.close {
				position: absolute;
				right: 0;
				top: 0;
				width: 50rpx;
				height: 50rpx;
				font-size: 40rpx;
				background: rgba(0, 0, 0, 0.7);
				color: #fff;
				border-radius: 50%;
				display: flex;
				justify-content: center;
				align-items: center;
				cursor: pointer;
			}
		}

		.add {
			font-size: 80rpx;
			display: flex;
			align-items: center;
			justify-content: center;
			color: #888;


		}
	}
</style>